/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "utils.h"
#include "vector.h"

#include <assert.h>

namespace tri {
namespace utils {

void sleep(long milli) {
#ifdef WIN32
    Sleep(milli);
#else
    sleep(milli);
#endif
}

int random(int min, int max){
	int diff = max - min;
	if (diff==0){
		return max;
	}
	return min + ( rand()% diff);
}

float randomFloat(float min, float max, int prec){
	float factor = (rand()%prec) / (float)prec;
	float diff = max-min;
	
 	return min + ( diff*factor );
}

tri::TVector randomVector(float minx, float maxx,
					float miny, float maxy,
					float minz, float maxz,
					int prec){
	return tri::TVector(randomFloat(minx,maxx,prec),
					randomFloat(miny,maxy,prec),
					randomFloat(minz,maxz,prec));
}

TVector randomVector(tri::TVector min,
		tri::TVector max,
					int prec){
	return tri::TVector(randomFloat(min.x,max.x,prec),
					randomFloat(min.y,max.y,prec),
					randomFloat(min.z,max.z,prec));
}

bool isPow2(int v){
    int n = 1;
    while (n <= v){
        if (v==n&&n!=1){
            return true;
        }
        n *= 2;
    };
    return false;
}

int nextPow2(int v){
    if(v<=0){
        return v;
    }
    int n = 1;
    while (n <= v){
        n = n * 2;
    }
    return n;
}

int string2Int(const char * s ){
    return atoi(s);
}

float string2Float(const char * s){
    return atof(s);
}

long string2Long(const char * s){
    return atol(s);
}

bool isNumber(std::string n){

	bool found_decimal = false;
	for (unsigned int i = 0;i<n.size();i++){
		
		char c =  n.c_str()[i];
		if (c == '-'){
			if (i!=0){
				return false;
			}
			continue;
		}
		if( c == '.' ){
			if(!found_decimal){
				found_decimal = true;
			}else{
				return false;
			}
		}
		if ( ( c < '0' || c > '9' ) && c != '.' ){
			return false;
		}
	}
	
	return true;
}

std::string int2String(int i,int base){
    char buffer[20];
    sprintf(buffer,"%d",i);
//    itoa(i,buffer,base);
    return std::string(buffer);
}

std::string float2String(float a){
	return getFormatString("%.3f",a);
}

void quit(){
	exit(1);
}

std::string toUpper(std::string myString){
  std::string ret;
  const int length = myString.length();
  for(int i=0; i!=length ; ++i)
  {
    ret.append(1,std::toupper(myString[i]));
  }
  return ret;
}

bool startsWith(std::string str,std::string pref){
	if (pref.size() > str.size()){
		return false;
	}
	
	if (pref.size() == str.size()){
		return pref==str;
	}
	
	for (unsigned int i = 0; i < pref.size();i++){
		if ( pref.c_str()[i] != str.c_str()[i]){
			return false;
		}
	}
	
	return true;
}

float max(float f1,float f2){
	return f1>f2?f1:f2;
}

float ABS(float v){
	return v<0?-1*v:v;
}

float radToDeg(float rad){
	return rad*(180.0f/M_PI);
}

float degToRad(float deg){
	return deg*(M_PI/180.0f);
}

std::string getFormatString(const char* fmt,...){
	char text[1024]; // Holds Our String
    va_list ap; // Pointer To List Of Arguments

    if (fmt == NULL) { // If There's No Text
        return "";
    } else {
        
        va_start(ap, fmt);
        // Parses The String For Variables
        vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
        va_end(ap);
        // Results Are Stored In Text
    }
    return std::string(text);
}

void bubbleSortList4Uint32(unsigned int *a,int size,int hotIndex){
    
    assert(size%4==0);
    assert(hotIndex >= 0 && hotIndex <= 3);
    int c = size/4;
    
    for(int pass=1;pass<c;pass++){
            for(int i=0;i<4*(c-1);i+=4){
                if(a[i+hotIndex]>a[i+4+hotIndex]){
                    unsigned int hold1 = a[i];
                    unsigned int hold2 = a[i+1];
                    unsigned int hold3 = a[i+2];
                    unsigned int hold4 = a[i+3];
                    
                    a[i]= a[i+4];
                    a[i+1]= a[i+5];
                    a[i+2]= a[i+6];
                    a[i+3]= a[i+7];
                    
                    a[i+4] = hold1;
                    a[i+5] = hold2;
                    a[i+6] = hold3;
                    a[i+7] = hold4;
                                    
                }
            }
        }
}

void bubbleSortList4Uint32Decend(unsigned int *a,int size,int hotIndex){
    
    assert(size%4==0);
    assert(hotIndex >= 0 && hotIndex <= 3);
    int c = size/4;
    
    for(int pass=1;pass<c;pass++){
            for(int i=0;i<4*(c-1);i+=4){
                if(a[i+hotIndex]<a[i+4+hotIndex]){
                    unsigned int hold1 = a[i];
                    unsigned int hold2 = a[i+1];
                    unsigned int hold3 = a[i+2];
                    unsigned int hold4 = a[i+3];
                    
                    a[i]= a[i+4];
                    a[i+1]= a[i+5];
                    a[i+2]= a[i+6];
                    a[i+3]= a[i+7];
                    
                    a[i+4] = hold1;
                    a[i+5] = hold2;
                    a[i+6] = hold3;
                    a[i+7] = hold4;
                                    
                }
            }
        }
}

void fitToArea(float src_w,float src_h,float dst_ar,float &dst_w, float &dst_h){

        if(src_w/dst_ar <= src_h){
            dst_w = src_w;
            dst_h = src_w/dst_ar;
        }else{
            dst_h = src_h;
            dst_w = src_h*dst_ar;
        }
}

void split(std::vector<std::string>& split_str,std::string str,char split){
	split_str.clear();
	std::string ret = "";
	for (int i = 0; i<(int)str.size(); i++) {
		char c = str.c_str()[i];
		if (c == split ){
			split_str.push_back(ret);
			ret = "";
		}else{
			ret.append(1,c);
		}
    }
	
	if (ret != ""){
		split_str.push_back(ret);
	}
}

}
}
